from ..libmoops import verbose_print
from ..libmoops import (TEXT_ADDRESS, DATA_ADDRESS)
from operator import itemgetter

class Memory(object):
    def __init__(self):
        self.initialize()
        
        # are these for anything?
        #self.dataLength=5
        #self.instructionLength=0
        
    # convience functions
    def __getitem__(self, pc):
        return self.readMemory(pc)
    
    def __setitem__(self, pc, data):
        return self.writeMemory(pc, data)

    def writeMemory(self, pc, data):
        if isinstance(data, int):
            verbose_print("Writing 0x%08x to 0x%08x"%(data, pc))
            # print("Memory write "  +hex(pc)) # please use verbose_print or debug_print!
            if (pc >= 0x00000000 and pc < 0x80000000):
                self.kuser[pc] = data
            elif (pc >= 0x80000000 and pc < 0xa0000000):
                self.kseg0[pc] = data
            elif (pc >= 0xa0000000 and pc < 0xc0000000):
                self.kseg1[pc] = data
            elif (pc >= 0xc0000000 and pc <= 0xffffffff):
                self.kseg2[pc] = data
        elif data:
            # this means we (should) have an iterable to write all at once
            verbose_print("-= BEGIN BATCH WRITE =-")
            for index, datum in enumerate(data):
                self.writeMemory(pc + index * 4, datum)
            verbose_print("-= END BATCH WRITE =-")

    def readMemory(self, pc):
        if (self.exist(pc)):
            if (pc >= 0x00000000 and pc < 0x80000000):
                return self.kuser[pc]
            elif (pc >= 0x80000000 and pc < 0xa0000000):
                return self.kseg0[pc]
            elif (pc >= 0xa0000000 and pc < 0xc0000000):
                return self.kseg1[pc]
            elif (pc >= 0xc0000000 and pc <= 0xffffffff):
                return self.kseg2[pc]
        else:
            return 0
            
    def readWord(self, pc):
        pcOffset = pc % 2
        #print("pcOffset " + str(pcOffset))
        data = self.readMemory(pc - pcOffset) #rounds down to the nearest whole instruction
        #print("data " + hex(data))
        #may need to reverse returns depending on endian
        #return (data >> (16 - pcOffset * 8 )) & 0xffff
        print("not yet implemented")
        return 1
    
    def readByte(self, pc):
        pcOffset = (pc % 4)
        data = self.readMemory(pc - pcOffset) #rounds down to the nearest whole instruction
        #may need to reverse returns depending on endian
        return (data >> (8*(pcOffset))) & 0xff
        
    def exist(self, pc):
        if (pc in self.kuser) | (pc in self.kseg0) | (pc in self.kseg1) | (pc in self.kseg2):
            return True
        else:
            return False

    # perhaps rename this to clear?
    def initialize(self):
        #self.memory = {}
        self.kuser = {}
        self.kseg0 = {}
        self.kseg1 = {}
        self.kseg2 = {}